package com.syh.jn.scm.infrastructure.repository.impl.supplier.base.downstream;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.wrapper.Wrapper;
import com.syh.core.ddd.infrastructure.repository.AbstractAggregateRepository;
import com.syh.jn.scm.domain.supplier.entity.base.downstream.Downstream;
import com.syh.jn.scm.domain.supplier.entity.base.downstream.DownstreamAddress;
import com.syh.jn.scm.domain.supplier.repository.base.downstream.DownstreamRepository;
import com.syh.jn.scm.dto.supplier.base.downstream.DownstreamAddressVo;
import com.syh.jn.scm.dto.supplier.base.downstream.DownstreamVo;
import com.syh.jn.scm.infrastructure.repository.model.base.BusinessEntityAddressModel;
import com.syh.jn.scm.infrastructure.repository.model.base.SalesmanModel;
import com.syh.jn.scm.infrastructure.repository.model.base.downstream.DownstreamCategoryModel;
import com.syh.jn.scm.infrastructure.repository.model.base.downstream.DownstreamModel;
import com.syh.jn.scm.infrastructure.repository.model.base.downstream.DownstreamPriceTemplateModel;
import com.syh.jn.scm.infrastructure.repository.model.system.AccountModel;
import com.syh.jn.scm.infrastructure.repository.utils.SQLAliasGenerateUtil;
import com.syh.jn.scm.infrastructure.wrapper.BaseResolve;
import com.syh.jn.scm.infrastructure.wrapper.ResolveToSQL;
import org.apache.ibatis.jdbc.SQL;
import org.hibernate.Query;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Repository
public class DownstreamRepositoryImpl extends AbstractAggregateRepository<Downstream, DownstreamModel, Long> implements DownstreamRepository {
  @Override
  protected SQL getViewSql() {
    return new SQL() {{
      SELECT(
              SQLAliasGenerateUtil.aliasGenerate(DownstreamModel.class, "downstream", null
                      , new String[]{"categoryName", "salesmanName", "priceTemplateName"}),
              "salesMan.name as salesmanName",
              "cate.name as categoryName",
              "goodsPriceTmpl.name as priceTemplateName",
              "account.ID AS accountId",
              "account.LOGIN_ACCOUNT AS account"

      );
      FROM(getModelTableName(DownstreamModel.class) + " downstream");
      LEFT_OUTER_JOIN(getModelTableName(SalesmanModel.class) + " salesMan on downstream.SALESMAN_ID = salesMan.ID");
      LEFT_OUTER_JOIN(getModelTableName(DownstreamPriceTemplateModel.class) + " goodsPriceTmpl on downstream.PRICE_TEMPLATE_ID = goodsPriceTmpl.ID");
      LEFT_OUTER_JOIN(getModelTableName(DownstreamCategoryModel.class) + " cate on downstream.CATEGORY_ID = cate.ID");
      LEFT_OUTER_JOIN(getModelTableName(AccountModel.class) + " account on downstream.ID = account.BUSINESS_ENTITY_ID  and account.TERMINAL_TYPE = 'DOWNSTREAM' and account.ADMIN = 1 and account.ROLE_ID = 0");
    }};
  }

  @Override
  protected Class getViewObject() {
    return DownstreamVo.class;
  }

  @Override
  protected BaseResolve getViewWrapperResolve(Wrapper wrapper) {
    Map<String, String> params = new HashMap<>();
    params.put("id", "downstream.ID");
    params.put("name", "downstream.NAME");
    params.put("id", "downstream.ID");
    params.put("registrationCode", "downstream.REGISTRATION_CODE");
    params.put("status", "downstream.STATUS");
    params.put("legalRepresentative", "downstream.LEGAL_REPRESENTATIVE");
    params.put("businessEntityId", "downstream.BUSINESS_ENTITY_ID");
    ResolveToSQL parse = new ResolveToSQL(wrapper, (propertyName) -> {
      return params.get(propertyName);
    });
    return parse;
  }

  /**
   * 增加下游以及下游客户地址
   *
   * @param downstream
   * @return
   */
  @Override
  public Long add(Downstream downstream) {
    Long id = super.add(downstream);
    downstream.getAddressesItem().forEach((item) -> {
      this.addAddress(id, item);
    });
    return id;
  }

  /**
   * 更改下游以及下游地址
   *
   * @param downstream
   */
  @Override
  public void update(Downstream downstream) {
    this.update(downstream, true);
  }

  public void update(Downstream downstream, Boolean isUpdateAddress) {
    super.update(downstream);

    if (isUpdateAddress) {
      this.removeAllAddress(downstream);
      downstream.getAddressesItem().forEach(item -> {
        this.addAddress(downstream.getId(), item);
      });
    }
  }

  public DownstreamAddress getAddressById(Long addressId) {
    BusinessEntityAddressModel addressModel = this.hibernateTemplate.get(BusinessEntityAddressModel.class, addressId);
    // 区分地址归属哈
    if (addressModel.getTerminalType().equals("DOWNSTREAM")) {
      return null;
    }
    return ExtBeanUtils.copyProperties(addressModel, new DownstreamAddress(), true);
  }

  public List<DownstreamAddress> getAddressByDownstreamId(Long downstreamId) {
    List<BusinessEntityAddressModel> businessEntityAddressModelList =
            (List<BusinessEntityAddressModel>) this.hibernateTemplate.find("from BusinessEntityAddressModel model where model.businessEntityId = ?", downstreamId);

    List<DownstreamAddress> downstreamAddressList = businessEntityAddressModelList.stream().map((item -> {
      return ExtBeanUtils.copyProperties(item, new DownstreamAddress(), true);
    })).collect(Collectors.toList());

    return downstreamAddressList;
  }

  protected Long addAddress(Long id, DownstreamAddress address) {
    BusinessEntityAddressModel addressModel = new BusinessEntityAddressModel();
    ExtBeanUtils.copyProperties(address, addressModel);
    addressModel.setBusinessEntityId(id);
    addressModel.setTerminalType("DOWNSTREAM");
    return (Long) this.hibernateTemplate.save(addressModel);
  }

  protected Long updateAddress(DownstreamAddress address) {
    BusinessEntityAddressModel addressModel = new BusinessEntityAddressModel();
    ExtBeanUtils.copyProperties(address, addressModel);
    return (Long) this.hibernateTemplate.save(addressModel);
  }

  protected Long removeAddress(DownstreamAddress address) {
    BusinessEntityAddressModel addressModel = new BusinessEntityAddressModel();
    ExtBeanUtils.copyProperties(address, addressModel);
    return (Long) this.hibernateTemplate.save(addressModel);
  }

  protected void removeAllAddress(Downstream downstream) {
    Query query = this.buildQuery("delete BusinessEntityAddressModel model where model.businessEntityId = :businessEntityId and model.terminalType = 'DOWNSTREAM' ");
    query.setLong("businessEntityId", downstream.getId());
    query.executeUpdate();
  }


  /**
   * 删除下游以及下游地址
   *
   * @param downstream
   */
  @Override
  public void remove(Downstream downstream) {
    Query query = this.buildQuery("delete BusinessEntityAddressModel model where model.businessEntityId = :businessEntityId  and model.terminalType = 'DOWNSTREAM'");
    query.setLong("businessEntityId", downstream.getId());
    query.executeUpdate();
    super.remove(downstream);
  }


  /**
   * 根据客户id拿到地址
   *
   * @param downstreamId
   * @return
   */
  @Override
  public List<DownstreamAddressVo> getDownstreamAddressView(Long downstreamId) {
    StringBuffer hql = new StringBuffer();
    hql.append("from BusinessEntityAddressModel model where model.businessEntityId = ? and model.terminalType = 'DOWNSTREAM'");
    List<BusinessEntityAddressModel> model = (List<BusinessEntityAddressModel>) this.hibernateTemplate.find(hql.toString(), downstreamId);
    List<DownstreamAddress> addressList = new ArrayList<>();
    model.stream().forEach(item -> {
      DownstreamAddress address = new DownstreamAddress();
      ExtBeanUtils.copyProperties(item, address);
      addressList.add(address);
    });
    return this.transformDownstream(addressList);
  }

  /**
   * 内部方法  业务模型转DownstreamCustomerAddressVo
   *
   * @param entityList
   * @return
   */
  private List<DownstreamAddressVo> transformDownstream(List<DownstreamAddress> entityList) {
    List<DownstreamAddressVo> voList = new ArrayList<>();
    entityList.stream().forEach((entity) -> {
      DownstreamAddressVo vo = new DownstreamAddressVo();
      ExtBeanUtils.copyProperties(entity, vo);
      voList.add(vo);
    });
    return voList;
  }
}
